/*
	TODO - All functions should be able to handle an expired access token
	
	Sample transfer list with one file
		{
			"status": "success",
			"data": [
				[
					{
						"token": "whatevertoken",
						"name": "debian-9.4.0-amd64-netinst.iso",
						"status": "downloading",
						"downloadedPart": 0.66,
						"size": "291 MB",
						"downloadSpeed": "12.69 MB/s",
						"uploadSpeed": "394.06 kB/s",
						"completedLength": "194.72 MB",
						"remainingTime": "8 seconds",
						"currentlyFindingSeeds": false
					}
				]
			],
			"errors": null
		}

	Sample transfer info
		{
			"status": "success",
			"data": [
				{
					"token": "whatevertoken",
					"name": "debian-9.4.0-amd64-netinst.iso",
					"status": "downloading",
					"downloadedPart": 0.71,
					"size": "291 MB",
					"downloadSpeed": "13.83 MB/s",
					"uploadSpeed": "394.06 kB/s",
					"completedLength": "208.56 MB",
					"remainingTime": "6 seconds",
					"currentlyFindingSeeds": false
				}
			],
			"errors": null
		}
	Sample add torrent return value
		<h1>Redirect</h1>
		<p><a href="https://api.bitport.io/v2/transfers/whatevertoken">Please click here to continue</a>.</p>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
#include <pwd.h> // get home dir
#include <sys/stat.h> // mkdir
#include <curl/curl.h>
#include "BorrowedCode/cJSON.h"
/*============================================================================*/
#include "main.h"
#include "platformSpecific.h"
#include "curlEasy.h"
#include "secret.h" // IN THIS FILE, use #define to define, as a string, TESTAPPID and TESTAPPSECRET
#include "gui.h"
/*============================================================================*/
int totalStatuses=0;
singleStatus* myStatuses=NULL;

int totalFileInfos=0;
fileInfo* myFileInfos=NULL;
fileInfo currentFolderParent;
char* currentBrowserDir=NULL;

char* homeDir;
char* configDir;
char* downloadsDir;

int totalHDDL=0;
downloadInstance** currentHDDL=NULL;

CURL* _generalUseCurl; // Only use from main thread
char* _userAccessToken;
/*============================================================================*/
#define getUserCodePOSTFormat "client_id=%s&client_secret=%s&grant_type=code&code=%s"
#define ENABLECACHEACCESS 1
#define TESTTORRENT "https://cdimage.debian.org/debian-cd/current/amd64/bt-cd/debian-9.4.0-amd64-netinst.iso.torrent"
#define REGULARDOWNLOADFORMAT "/v2/files/%s/download"
#define FOLDERDOWNLOADFORMAT "/v2/cloud/%s/download-as-zip"
/*============================================================================*/
void changeMallocString(char** _passedMallocString, char* _newString){
	free(*_passedMallocString);
	if (_newString!=NULL){
		*_passedMallocString = strdup(_newString);
	}else{
		*_passedMallocString=NULL;
	}
}
void resetFileInfos(){
	int i;
	for (i=0;i<totalFileInfos;++i){
		free(myFileInfos[i].filename);
		free(myFileInfos[i].filecode);
		//gtk_widget_destroy(myFileInfos[i].internalWidget);
	}
	totalFileInfos=0;
	free(myFileInfos);
	myFileInfos=NULL;
}
fileInfo* addFileInfo(){
	totalFileInfos++;
	myFileInfos = realloc(myFileInfos,sizeof(fileInfo)*totalFileInfos);
	myFileInfos[totalFileInfos-1].filename=NULL;
	myFileInfos[totalFileInfos-1].filecode=NULL;
	//myFileInfos[totalFileInfos-1].internalWidget=NULL;
	myFileInfos[totalFileInfos-1].isFolder=0;
	return &(myFileInfos[totalFileInfos-1]);
}
// Sort by name with folders on top
void sortFileInfo(){
	int i;
	char _oneSwapped;
	do{
		_oneSwapped=0;
		for (i=1;i<totalFileInfos;++i){
			if ((strcmp(myFileInfos[i].filename,myFileInfos[i-1].filename)<0 && (myFileInfos[i].isFolder==myFileInfos[i-1].isFolder)) || (myFileInfos[i].isFolder==1 && myFileInfos[i-1].isFolder==0)){
				fileInfo _tempSwap = myFileInfos[i-1];
				myFileInfos[i-1] = myFileInfos[i];
				myFileInfos[i] = _tempSwap;
				_oneSwapped=1;
			}
		}
	}while(_oneSwapped);
}
void updateFileInfo(CURL* _passedCurl, char* _passedFolderCode){
	// Either the passed folder code or an empty string
	char* _extraString = _passedFolderCode!=NULL ? _passedFolderCode : "";
	char _assembledString[strlen(WEBSITEPREFIX)+strlen("/v2/cloud")+strlen(_extraString)+2]; // Plus 2 because if we have a folder code, we need a slash
	strcpy(_assembledString,WEBSITEPREFIX);
	strcat(_assembledString,"/v2/cloud");
	if (_passedFolderCode!=NULL){
		strcat(_assembledString,"/");
	}
	strcat(_assembledString,_extraString);

	// Just a simple GET request
	resetCurlSettings(_passedCurl);
	struct curl_slist* _apiRequestHeader = newCurlHeaders();
	prepareAPIHeader(_userAccessToken,&_apiRequestHeader);
	applyCurlHeaders(_passedCurl,_apiRequestHeader);
	memoryStruct _gottenWebpageData;
	downloadWebpageData(_passedCurl,&_gottenWebpageData,_assembledString);

	if (_gottenWebpageData.memory!=NULL){
		cJSON* _webResponseJson = cJSON_Parse(_gottenWebpageData.memory);
		if (_webResponseJson==NULL){
			printf("Could not parse json.");
		}else{
			cJSON* _responseStatus = cJSON_GetObjectItemCaseSensitive(_webResponseJson, "status");
			if (strcmp(_responseStatus->valuestring,"success")!=0){
				printf("Bitport returned error status.\n");
			}else{
				resetFileInfos();


				cJSON* _foundArray = cJSON_GetObjectItemCaseSensitive(_webResponseJson, "data");
				_foundArray = cJSON_GetArrayItem(_foundArray,0);
				cJSON* _foundFolders = cJSON_GetObjectItemCaseSensitive(_foundArray, "folders");
				cJSON* _foundFiles = cJSON_GetObjectItemCaseSensitive(_foundArray, "files");
				cJSON* _foundParentFolder = cJSON_GetObjectItemCaseSensitive(_foundArray, "parent_folder");

				// Set variable for name of the folder we're browsing in
				changeMallocString(&currentBrowserDir,cJSON_GetObjectItem(_foundArray, "name")->valuestring);

				// Set up data about the parent folder.
				free(currentFolderParent.filename);
				free(currentFolderParent.filecode);
				if (_foundParentFolder->type!=cJSON_NULL){
					currentFolderParent.filename = strdup(cJSON_GetObjectItem(_foundParentFolder, "name")->valuestring);
					cJSON* _possibleFilecode = cJSON_GetObjectItem(_foundParentFolder, "code");
					if (_possibleFilecode->type!=cJSON_NULL){
						currentFolderParent.filecode = strdup(_possibleFilecode->valuestring);
					}else{
						currentFolderParent.filecode=NULL;
					}
				}else{
					currentFolderParent.filename=NULL;
					currentFolderParent.filecode=NULL;
				}
				// If we have a parent folder, add it to the file list.
				if (currentFolderParent.filename!=NULL){
					fileInfo* _newEntry = addFileInfo();
					_newEntry->filename = strdup("..");
					if (currentFolderParent.filecode!=NULL){
						_newEntry->filecode = strdup(currentFolderParent.filecode);
					}else{
						_newEntry->filecode=NULL;
					}
					_newEntry->isFolder=1;
				}
				// Add to the array the folders are files in this directory
				int i;
				int _cachedSize = cJSON_GetArraySize(_foundFolders);
				for (i=0;i<_cachedSize;++i){
					cJSON* _currentArrayElement = cJSON_GetArrayItem(_foundFolders, i);
					fileInfo* _newEntry = addFileInfo();
					_newEntry->filename = strdup(cJSON_GetObjectItemCaseSensitive(_currentArrayElement, "name")->valuestring);
					_newEntry->filecode = strdup(cJSON_GetObjectItemCaseSensitive(_currentArrayElement, "code")->valuestring);
					_newEntry->isFolder=1;
				}
				_cachedSize = cJSON_GetArraySize(_foundFiles);
				for (i=0;i<_cachedSize;++i){
					cJSON* _currentArrayElement = cJSON_GetArrayItem(_foundFiles, i);
					fileInfo* _newEntry = addFileInfo();
					_newEntry->filename = strdup(cJSON_GetObjectItemCaseSensitive(_currentArrayElement, "name")->valuestring);
					_newEntry->filecode = strdup(cJSON_GetObjectItemCaseSensitive(_currentArrayElement, "code")->valuestring);
					_newEntry->isFolder=0;
				}

				sortFileInfo();
			}
		}
		cJSON_Delete(_webResponseJson);
	}else{
		printf("Website data was NULL.\n");
	}

	free(_gottenWebpageData.memory);
}

void _deleteAStatusSp(singleStatus* _passedStatus, char _doFree){
	if (_doFree){
		free(_passedStatus->filename);
		free(_passedStatus->token);
	}
	_passedStatus->filename=NULL;
	_passedStatus->token=NULL;
	_passedStatus->healthBar = HP_DEAD;
}

void deleteAStatus(singleStatus* _passedStatus){
	_deleteAStatusSp(_passedStatus,1);
}

// Gives you a new singleStatus pointer in the torrentStatuses
singleStatus* increaseTorrentArray(){
	int i;
	// First check if there's an empty slot we can use.
	for (i=0;i<totalStatuses;++i){
		if (myStatuses[i].healthBar==HP_DEAD){
			return &(myStatuses[i]);
		}
	}

	++totalStatuses;
	myStatuses = realloc(myStatuses,sizeof(singleStatus)*totalStatuses);
	// Here I must initialize all variables in the struct
	myStatuses[totalStatuses-1].filename=NULL;
	myStatuses[totalStatuses-1].token=NULL;
	myStatuses[totalStatuses-1].healthBar=HP_NORMAL;
	myStatuses[totalStatuses-1].timeLeft=NULL;

	return &(myStatuses[totalStatuses-1]);
}

// Searches the myStatuses array for the passed token. If found, returns pointer to the status for that token's torrnet. Otherwise NULL.
singleStatus* searchStatusesForToken(char* _passedToken){
	int i;
	for (i=0;i<totalStatuses;++i){
		if (myStatuses[i].token!=NULL){
			if (strcmp(myStatuses[i].token,_passedToken)==0){
				return &(myStatuses[i]);
			}
		}
	}
	return NULL;
}

// Will get the user's active torrents and update their names and progress in te myStatuses array.
// Will add new torrents if found in the API
void updateTorrentStatuses(CURL* _passedCurl){
	int i;
	for (i=0;i<totalStatuses;++i){
		if (myStatuses[i].healthBar==HP_NORMAL){
			myStatuses[i].healthBar = HP_NEEDSAVING; // If this torrent is not found in the progress now, delete it from the torrent statuses
		}else if (myStatuses[i].healthBar>0){
			--myStatuses[i].healthBar;
			if (myStatuses[i].healthBar==0){
				myStatuses[i].healthBar=HP_NEEDSAVING; // No HP left, if it's not found now, it'll be gone.
			}
		}else{
			printf("Error, invalid healthBar %d for index %d\n",myStatuses[i].healthBar,i);
		}
	}

	char* _foundTestTransfers = getActiveTransfersJSON(_passedCurl,_userAccessToken);
	if (_foundTestTransfers!=NULL){
		// Parse result to get what we need
		cJSON* _webResponseJson = cJSON_Parse(_foundTestTransfers);
		if (_webResponseJson==NULL){
			printf("Could not parse json.");
		}else{
			cJSON* _foundArray = cJSON_GetObjectItemCaseSensitive(_webResponseJson, "data");
			_foundArray = cJSON_GetArrayItem(_foundArray,0); // First element of our data array is an anonymous array of what we're really looking for
			for (i=0;i<cJSON_GetArraySize(_foundArray);++i){
				cJSON* gottenElemenet;
				char* _foundToken;
				char* _foundTimeLeft;
				double _foundProgress;
				cJSON* _currentArrayElement = cJSON_GetArrayItem(_foundArray, i);

				gottenElemenet = cJSON_GetObjectItem(_currentArrayElement, "token");
				_foundToken = gottenElemenet->valuestring;

				gottenElemenet = cJSON_GetObjectItem(_currentArrayElement, "downloadedPart");
				_foundProgress = gottenElemenet->valuedouble;

				gottenElemenet = cJSON_GetObjectItem(_currentArrayElement, "remainingTime");
				_foundTimeLeft = gottenElemenet->valuestring;
				if (_foundTimeLeft==NULL){
					_foundTimeLeft=""; // Prevent crashes maybe
				}
				////
				singleStatus* _possibleUpdatableElement = searchStatusesForToken(_foundToken);
				if (_possibleUpdatableElement!=NULL){
					if (_possibleUpdatableElement->filename==NULL){
						gottenElemenet = cJSON_GetObjectItem(_currentArrayElement, "name");
						_possibleUpdatableElement->filename = strdup(gottenElemenet->valuestring);
					}
					if (_possibleUpdatableElement->timeLeft!=NULL){
						free(_possibleUpdatableElement->timeLeft);
					}
					_possibleUpdatableElement->timeLeft = strdup(_foundTimeLeft);
				}else{ // Add a new element if not found in the array already
					_possibleUpdatableElement = increaseTorrentArray();

					gottenElemenet = cJSON_GetObjectItem(_currentArrayElement, "name");
					_possibleUpdatableElement->filename = strdup(gottenElemenet->valuestring);
					_possibleUpdatableElement->token = strdup(_foundToken);
					_possibleUpdatableElement->progress = _foundProgress;
					_possibleUpdatableElement->timeLeft = strdup(_foundTimeLeft);
				}
				_possibleUpdatableElement->progress = _foundProgress;
				_possibleUpdatableElement->healthBar = HP_NORMAL;
			}
		}
		cJSON_Delete(_webResponseJson);

		for (i=0;i<totalStatuses;++i){
			if (myStatuses[i].healthBar==HP_NEEDSAVING){
				printf("R.I.P, index %d\n",i);
				deleteAStatus(&(myStatuses[i]));
			}
		}
	}else{
		printf("could not get.\n");
	}
	free(_foundTestTransfers);


	// Delete any unused transfers from the array
	for (i=1;i<totalStatuses;++i){
		if (myStatuses[i].healthBar!=HP_DEAD){ // We don't care about long strings of invalid entries
			if (myStatuses[i-1].healthBar==HP_DEAD){
				int j;
				// Find how far back we have to shift. j will equal the last invalid entry
				// Can't start at j-2 because that could start at -1.
				for (j=i-1;j>=0;--j){
					if (myStatuses[j].healthBar!=HP_DEAD){
						break;
					}
				}
				int _lastDeadEntry = j+1; // Add 1 because look breaks at a valid entry or -1 index.
				for (j=i;j<totalStatuses;++j){
					// Move all array elements that are to the right of the invalid entry the same amount to the left relative.
					myStatuses[j-(i-_lastDeadEntry)] = myStatuses[j];
					// Mark old element as invalid array element
					_deleteAStatusSp(&(myStatuses[j]),0);
				}
			}
		}
	}
	int _newTotalStatuses=0;
	for (i=0;i<totalStatuses;++i){
		if (myStatuses[i].healthBar!=HP_DEAD){
			_newTotalStatuses++;
		}else{
			break; // Assuming above code worked and the rest will be invalid entries
		}
	}
	totalStatuses = _newTotalStatuses;
	myStatuses = realloc(myStatuses,sizeof(singleStatus)*totalStatuses); // Will delete all the invalid entries
}

void printDivider(){
	printf("==========================\n");
}

#define LOGFILEPREFIX "./log/file"
void dumpLogFile(char* _string){
	printf("Attempting to dump log file...\n");
	char _filenameBuffer[strlen(LOGFILEPREFIX)+8]; // Up to LOGFILEPREFIX9999999
	uint16_t i;
	// Find open file slot
	for (i=0;i<10000;++i){
		sprintf(_filenameBuffer,"%s%d",LOGFILEPREFIX,i);
		if(fileExists(_filenameBuffer)==0) {
			// Write data to open file slot
			FILE* fp = fopen(_filenameBuffer,"w");
			if (fp!=NULL){
				fwrite(_string,strlen(_string),1,fp);
				fclose(fp);
				printf("Log dumped to %s\n",_filenameBuffer);
			}else{
				printf("Could not open %s, could not dump log file.\n",_filenameBuffer);
			}
			break;
		}
	}
}

// Add the access token to the headers
void prepareAPIHeader(char* _passedUserToken, struct curl_slist** _passedHeaders){
	char _totalContentString[strlen("Authorization: Bearer ")+strlen(_passedUserToken)+1];
		strcpy(_totalContentString,"Authorization: Bearer ");
		strcat(_totalContentString,_passedUserToken);
	*_passedHeaders = curl_slist_append(*_passedHeaders, _totalContentString);
}

char* getAccessToken(CURL* _passedCurl, const char* _passedCode){
	resetCurlSettings(_passedCurl);
	
	// Set content-type to application/x-www-form-urlencoded because the docs told me to.
	// ---
	// Actually, don't. That's the default.
	//struct curl_slist* _myCurlHeaders = newCurlHeaders();
	//curlSetContentType("application/x-www-form-urlencoded",&_myCurlHeaders);
	//applyCurlHeaders(_passedCurl,_myCurlHeaders);
	
	// Prepare POST data
	char _completePostData[strlen(getUserCodePOSTFormat)+strlen(TESTAPPID)+strlen(_passedCode)+strlen(TESTAPPSECRET)+1];
	sprintf(_completePostData,getUserCodePOSTFormat,TESTAPPID,TESTAPPSECRET,_passedCode);
	setUpCurlPost(_passedCurl,_completePostData);
	
	// Do
	memoryStruct _gottenWebpageData;
	downloadWebpageData(_passedCurl,&_gottenWebpageData,WEBSITEPREFIX"/v2/oauth2/access-token");
	//freeCurlHeaders(_myCurlHeaders);

	// Parse result to get what we need
	cJSON* _webResponseJson = cJSON_Parse(_gottenWebpageData.memory);
	char* _returnString=NULL;
	if (_webResponseJson==NULL){
		printf("Could not parse json. %s\n",_gottenWebpageData.memory);
	}else{
		cJSON* _foundKeyJson = cJSON_GetObjectItemCaseSensitive(_webResponseJson, "access_token");
		if (_foundKeyJson!=NULL){
			_returnString = strdup(_foundKeyJson->valuestring);
		}else{
			printf("Failed to get access_token in the response JSON\n");
			printf("%s\n",_gottenWebpageData.memory);
		}
	}
	cJSON_Delete(_webResponseJson);

	free(_gottenWebpageData.memory);
	return _returnString;
}

char* readStringFile(char* _filename){
	char* _loadedStringBuffer;
	FILE* fp = fopen(_filename, "rb");
	if (fp==NULL){
		return NULL;
	}
	// Get file size
	fseek(fp, 0, SEEK_END);
	long _foundFilesize = ftell(fp);
	fseek(fp, 0, SEEK_SET);
	// Read file into memory
	_loadedStringBuffer = malloc(_foundFilesize+1);
	_loadedStringBuffer[_foundFilesize]='\0';
	fread(_loadedStringBuffer, _foundFilesize, 1, fp);
	fclose(fp);
	return _loadedStringBuffer;
}

// How to get list of transfers
// Returns the JSON of the active transfers as a malloc'd string
char* getActiveTransfersJSON(CURL* _passedCurl, char* _passedToken){
	resetCurlSettings(_passedCurl);

	// Make headers
	struct curl_slist* _apiRequestHeader = newCurlHeaders();
	prepareAPIHeader(_passedToken,&_apiRequestHeader);
	applyCurlHeaders(_passedCurl,_apiRequestHeader);

	// Do the request
	memoryStruct _gottenWebpageData;
	downloadWebpageData(_passedCurl,&_gottenWebpageData,WEBSITEPREFIX"/v2/transfers");
	freeCurlHeaders(_apiRequestHeader);

	return _gottenWebpageData.memory;
}

// Adding a torrent
// Returns the token for the torrent
// Can return NULL
char* addTorrentLink(CURL* _passedCurl, const char* _passedTorrentURL, char* _passedToken){
	resetCurlSettings(_passedCurl);
	
	// Make headers
	struct curl_slist* _apiRequestHeader = newCurlHeaders();
	prepareAPIHeader(_passedToken,&_apiRequestHeader);
	//curlSetContentType("application/x-www-form-urlencoded",&_apiRequestHeader);
	applyCurlHeaders(_passedCurl,_apiRequestHeader);
	
	// We're POST-ing the torrent link
	char _completePostString[strlen("torrent=")+strlen(_passedTorrentURL)+1];
		strcpy(_completePostString,"torrent=");
		strcat(_completePostString,_passedTorrentURL);
	setUpCurlPost(_passedCurl,_completePostString);

	// Do the web request
	memoryStruct _gottenWebpageData;
	downloadWebpageData(_passedCurl,&_gottenWebpageData,WEBSITEPREFIX"/v2/transfers");
	
	// Find the start of the link
	char* _linkStart = strstr(_gottenWebpageData.memory,"http");
	char* _foundReturnString = NULL;
	if (_linkStart!=NULL){
		strstr(_linkStart,"\"")[0]='\0'; // Don't worry about the rest of the string.
		_linkStart = &(_linkStart[strlen("https://api.bitport.io/v2/transfers/")]); // Skip the part we don't care about, trim start until we get to token
		_foundReturnString = strdup(_linkStart);
	}else{
		printf("Could not find link. The response was \n%s\n",_gottenWebpageData.memory);
	}

	// Cleanup
	freeCurlHeaders(_apiRequestHeader);
	free(_gottenWebpageData.memory);
	return _foundReturnString;
}

// DL file link
char* getHDDL(CURL* _passedCurl, const char* _fileCode, char* _passedToken, char _isFolder){
	resetCurlSettings(_passedCurl);
	curl_easy_setopt(_passedCurl, CURLOPT_FOLLOWLOCATION, 0L); // Need to intercept redirect URL

	// Make headers
	struct curl_slist* _apiRequestHeader = newCurlHeaders();
	prepareAPIHeader(_passedToken,&_apiRequestHeader);
	applyCurlHeaders(_passedCurl,_apiRequestHeader);

	char _fullPath[strlen(WEBSITEPREFIX)+strlen(FOLDERDOWNLOADFORMAT)+strlen(REGULARDOWNLOADFORMAT)+strlen(_fileCode)+1];
	if (!_isFolder){
		sprintf(_fullPath,WEBSITEPREFIX REGULARDOWNLOADFORMAT,_fileCode);
	}else{
		sprintf(_fullPath,WEBSITEPREFIX FOLDERDOWNLOADFORMAT,_fileCode);
	}

	memoryStruct _gottenWebpageData;
	downloadWebpageData(_passedCurl,&_gottenWebpageData,_fullPath);
	printf("%s\n",_gottenWebpageData.memory);

	char* _foundOut;
	curl_easy_getinfo(_passedCurl, CURLINFO_REDIRECT_URL, &_foundOut);

	// Cleanup
	freeCurlHeaders(_apiRequestHeader);
	free(_gottenWebpageData.memory);
	return strdup(_foundOut);
}

void saveCacheAccess(char* _access){
	char _completePath[strlen(configDir)+strlen("cacheaccess")+1];
	strcpy(_completePath,configDir);
	strcat(_completePath,"cacheaccess");
	FILE* fp = fopen(_completePath,"wb");
	if (fp!=NULL){
		fwrite(_access,1,strlen(_access),fp);
		fclose(fp);
	}else{
		printf("Failed to save cache access code.");
	}
}

char* getHomeDir(){
	char* _ret = getenv("HOME");
	if (!_ret) {
		struct passwd* pwd = getpwuid(getuid());
		if (pwd)
			_ret = pwd->pw_dir;
	}
	if (_ret==NULL){
		printf("Failed to get home directory.");
		return strdup("./");
	}else{
		if (_ret[strlen(_ret)-1]!='/'){
			char* _fixed = malloc(strlen(_ret)+2);
			strcpy(_fixed,_ret);
			strcat(_fixed,"/");
			return _fixed;
		}
	}
	return strdup(_ret);
}

/*============================================================================*/
int main(int argc, char *argv[]){
	homeDir = getHomeDir();
	
	downloadsDir = malloc(strlen(homeDir)+strlen("Downloads/")+1);
	sprintf(downloadsDir,"%sDownloads/",homeDir);
	mkdir(downloadsDir,0777); // TODO - Maybe I shouldn't create this.

	configDir = malloc(strlen(homeDir)+strlen(".bitport-ez/")+1);
	sprintf(configDir,"%s.bitport-ez/",homeDir);
	mkdir(configDir,0777);

	//
	currentFolderParent.filename=NULL;
	currentFolderParent.filecode=NULL;
	//
	globalInitCurl();
	_generalUseCurl = newCurl();

	printf("Getting access token ");

	char _completePath[strlen(configDir)+strlen("cacheaccess")+1];
	strcpy(_completePath,configDir);
	strcat(_completePath,"cacheaccess");
	_userAccessToken=readStringFile(_completePath);
	if (_userAccessToken!=NULL){
		printf("using cached access.\n");
	}else{
		printf("with the user code from the GUI.\n");
	}

	startgui();
	
	free(_userAccessToken);
	deleteCurl(_generalUseCurl);
	globalDeleteCurl();
}
